import store from '@/store.js';
import storage from '@/utils/ado-self/ado-storage';
import {
  clone, getQueryValue, getVmPageStatus,
  isEmptyObject,
  isNum,
  jump, safeEval,
  setUrlParam,
} from '@/utils/util.js';
import { isEqual, orderBy as _orderBy } from 'lodash';
import { mapMutations, mapState } from 'vuex';
import { getLowCodeExpVal } from '../low-code/low-code-util';
import { formatEvents, getMatchAdvEvents, getMatchAdvParams } from './advanced-linkage-util.js';

// 带参跳转
const jumpUrlWithAdvLinkage = (linkageDatas, vm) => {
  let _linkageDatas = linkageDatas.filter(n => n.hasLink);
  const newWinArr = _linkageDatas.filter(n => n.linkConf.isOpenNewPage);

  // 当前页面只有一个，只取最后一条数据在当前页面打开
  let selfWinArr = _linkageDatas.filter(n => !n.linkConf.isOpenNewPage);
  if (selfWinArr.length > 0) {
    selfWinArr = [selfWinArr[selfWinArr.length - 1]];
  }

  // 保证新页面打开的先处理
  _linkageDatas = [...newWinArr, ...selfWinArr];

  // 先把历史的清除，防止越累积越多
  const keyPrefix = 'visual_advancedLinkage_';
  for (const i in localStorage) {
    if (i.includes(keyPrefix)) {
      const time = Number(i.replace(/.*_(\d+)$/, '$1'));
      if (Date.now() - time > 30 * 60 * 1000) { // 只保留缓存30分钟，超时的缓存清除掉
        storage.remove(i);
      }
    }
  }

  _linkageDatas.forEach((n, i) => {
    const advLinkageId = `${i}_${new Date().getTime()}`;
    const storageKey = `${keyPrefix}${advLinkageId}`;
    storage.set(storageKey, n);

    let { jumpUrl } = n.linkConf;
    const { pageId, siteId } = n.linkConf;

    // 有事件才加传参
    if (n.events.length) {
      jumpUrl = setUrlParam('advLinkageId', advLinkageId, jumpUrl);
    }

    if (window.location.href.includes('debugger')) {
      jumpUrl += '&debugger=true';
    }
    if (window.location.href.includes('token')) {
      jumpUrl += `&token=${getQueryValue('token')}`;
    }
    if (n.linkConf.isOpenNewPage) {
      jump(jumpUrl);
    } else {
      const currentRoute = window.xVueWeb.app.config.globalProperties.$router.currentRoute.value;
      if (!n.linkConf.isOpenNewPage && pageId && siteId && n.linkConf.linkType === 'page' && siteId === currentRoute.params.siteId) {
        vm.$router.push({
          name: currentRoute.name,
          params: { pageId, siteId: window.xVueWeb.app.config.globalProperties.$router.currentRoute.value.params.siteId },
          query: { advLinkageId },
        });
      } else {
        jump(jumpUrl, false, vm);
        const url = window.location.href.replace(/advLinkageId=.*$/, '');
        if (jumpUrl.includes(url)) {
          setTimeout(window.location.reload, 20);
        }
      }
    }
  });
};

// 本页面联动，不跳转
const selfTriggerAdvLinkage = linkageDatas => {
  const _linkageDatas = linkageDatas.filter(n => !n.hasLink);
  store.commit('setAdvancedLinkage', _linkageDatas);
};

const getValByType = (item, srcValues, receivedEvents) => {
  let val = null;
  switch (item.equalTo) {
    case 'field': // 来源于数据面板的字段，貌似没用代码，可能为了兼容历史数据
      val = srcValues[item.field];
      break;
    case 'srcField': // 来源于数据面板的字段
      if (Array.isArray(srcValues)) { // 用于标签组件多选传参
        val = srcValues.map(n => n[item.srcField] );
      } else {
        val = srcValues[item.srcField];
      }
      break;
    case 'event': // 事件
      {
        const [evtKey, paramKey] = item.event.split('.');
        const evt = receivedEvents.find(n => n.eventKey === evtKey);
        if (!evt) {
          break;
        }
        if (paramKey) {
          val = evt.parameters[paramKey];
        } else {
          const vals = Object.entries(evt.parameters).map(([key, _val]) => _val);
          val = vals[0];
        }
      }
      break;
    case 'url': // url传参
      val = getQueryValue(item.urlKey);
      break;
    case 'inputVal': // 手动输入
      val = getInputVal(item);
      break;
    default:
      break;
  }
  return val;
};

const getInputVal = item=>{
  const path = '^{{[^{}]+?}}$';

  // 判断是表达式没有返回值的时候就返回空,常量返回就是常量
  if (item.inputVal && new RegExp(path).test(item.inputVal)) {
    const lowCodeValue = getLowCodeExpVal({ expression: item.inputVal });
    return lowCodeValue === item.inputVal ? '' : lowCodeValue;
  }
  return item.inputVal;
};
const replaceJumpUrl = (n, srcValues, receivedEvents) => {
  const { linkVars } = n.linkConf;
  if (linkVars && linkVars.length) {
    let { jumpUrl } = n.linkConf;
    jumpUrl = jumpUrl.replace(/\[([^\]]+)\]/g, (s, s1) => {
      const item = linkVars.find(n1 => n1.varKey === s1);
      if (!item) {
        return s;
      }

      let val = getValByType(item, srcValues, receivedEvents);
      val = (val !== null && val !== undefined) ? val : s;

      // 表格空白单元格会显示'-'
      if (!val || val === '-') {
        val = '';
      }
      return val;
    });
    n.linkConf.jumpUrl = jumpUrl;
  }
};

// 发出联动
const sendAdvancedLinkagge = ({ advancedLinkage = {}, wid, widgetName, srcValues, extKey = '', vm = null }) => {
  let { linkageDatas = [] } = advancedLinkage;

  linkageDatas = JSON.parse(JSON.stringify(linkageDatas));

  // 根据条件过滤
  linkageDatas = linkageDatas.filter(n => {
    let isMatch = true;
    if (n.conditions.length) {
      isMatch = n.conditions.every(n1 => {
        if (n1.srcField === '_formula') {
          // 字段字符替换成数字 'x+y>10' => '1+2>10'
          const formula = n1.value.replace(/[a-zA-Z_\u4e00-\u9fa5\d]+/g, s => {
            if (srcValues[s]) {
              return srcValues[s];
            }
            if (isNum(s)) {
              return s;
            }
            return '';
          });
          const isTrue = Boolean(safeEval(formula));
          return isTrue;
        }

        // 维度度量表单独返回
        if (extKey && extKey.indexOf('col') > -1) {
          return srcValues[extKey] === n1.value;
        }
        return String(srcValues[n1.srcField]) === String(n1.value);
      });
    }
    return isMatch;
  });

  // 如果符合有条件项，则执行有条件项的跳转或联动，否则执行无条件项的跳转或联动
  const noConditions = linkageDatas.filter(n => !n.conditions.length);
  const hasConditions = linkageDatas.filter(n => n.conditions.length);
  linkageDatas = hasConditions.length ? hasConditions : noConditions;

  linkageDatas.forEach(n => {
    n.wid = wid;
    n.widgetName = widgetName;
    n.extKey = extKey;
    n.events.forEach(n1 => {
      n1.params.forEach(n2 => {
        n2.sendTime = new Date().getTime();
        n2.evtParameterVal = getValByType(n2, srcValues, vm.receivedEvents);
      });
    });

    replaceJumpUrl(n, srcValues, vm.receivedEvents);
  });

  jumpUrlWithAdvLinkage(linkageDatas, vm);
  selfTriggerAdvLinkage(linkageDatas);
};

// -----------------------------------
export default {
  computed: {
    ...mapState({
      advancedLinkage: state => state.VisualComponentsModule.advancedLinkage,
    }),
  },
  created() {
    this.loadAdvLinkageFromStorage();
  },
  watch: {
    'advancedLinkage.linkageDatas'(linkageDatas, oldLinkageDatas) {
      if (linkageDatas.length === 0 && oldLinkageDatas.length === 0) {
        return;
      }
      const compEvtKeys = this.config.events.filter(n => n.type === 'in' && n.key).map(n => n.key);
      if (!compEvtKeys.length) {
        return;
      }

      let needUpdate = false;
      const newEvts = this.getMyEvents(linkageDatas, compEvtKeys);

      // 过滤只包含当前发送组件发出的事件key
      const sentEvtKeys = this.getSentEvtKeys();
      const inSentEvts = newEvts.some(n => sentEvtKeys.includes(n.evtKey));

      if (newEvts.length && inSentEvts) { // 当前组件有新接收事件必须更新
        needUpdate = true;
      } else { // 当前组件没新接收事件，但老接收事件有当前组件（点击右上角删除筛选条件情况），也必须更新
        const oldEvts = this.getMyEvents(oldLinkageDatas, compEvtKeys);
        needUpdate = !isEqual(oldEvts, newEvts);
      }

      if (needUpdate) {
        const pageStatus = getVmPageStatus(this);
        this.updateParams(pageStatus);
        this.debounceGetData();

        // 提供给搜索组件，或其他没数据面板的组件使用
        if (this.runAdvLinkage) {
          this.runAdvLinkage(newEvts);
        }
      }
    },

    // 路由跳转，清空高级事件联动，防止干扰loadAdvLinkageFromStorage初始化
    $route(to) {
      if (to.query?.advLinkageId) {
        delete window.visualComp.loadAdvLinkageDone;
      }
    },

  },
  methods: {
    ...mapMutations(['delAdvancedLinkageByWid']),

    addAdvancedLinkageParamsBySourceType(dataSourceType, params, matchParams) {
      let _params = params;
      const { sentByWid } = this.advancedLinkage;
      if (['xMiner', 'xMinerPublicDatabase', 'fabric', 'Dac'].includes(dataSourceType)) {
        if (!params) {
          _params = [];
        }
        _params = params.filter(n => !n.isAdvanced || (n.isAdvanced && n.wid !== sentByWid));
        for (let i = 0; i < matchParams.length; i++) {
          _params.push({
            sendTime: matchParams[i].sendTime,
            code: matchParams[i].evtParameterKey,
            value: matchParams[i].evtParameterVal,
            wid: matchParams[i].wid,
            isAdvanced: 1,
          });
        }

        _params = _orderBy(_params, 'sendTime', 'asc');

        return _params;
      } else if (dataSourceType === 'xTag') {
        let { conditions = [], sqlParams = [] } = params;
        conditions = conditions.filter(n => !n.isAdvanced || (n.isAdvanced && n.wid !== sentByWid));
        const item = {
          terms: [],
          isAdvanced: 1,
          wid: sentByWid,
        };
        const { terms } = item;

        for (let i = 0; i < matchParams.length; i++) {
          const { evtParameterKey: key, evtParameterVal: value } = matchParams[i];

          // conditions 部分
          terms.push({
            [key]: [value],
          });
          conditions.push(item);
          params.conditions = conditions;

          // sqlParams 部分
          sqlParams = sqlParams.filter(n => !n.isAdvanced || (n.isAdvanced && n.wid !== sentByWid));
          sqlParams.push({
            key,
            value,
            isAdvanced: 1,
            wid: sentByWid,
          });
        }
        if (!conditions.length) {
          conditions = [{}];
        }
        params.conditions = conditions;
      } else {}
      return null;
    },

    addAdvancedLinkageParams() {
      const { events } = this.config;
      if (!events) {
        return;
      }

      let matchEvents = getMatchAdvEvents(events);
      matchEvents = this.clearAdvDfEvents(matchEvents);
      const matchParams = getMatchAdvParams(matchEvents);

      let { data } = this.config.config;

      // 适配左xx右xx组件data格式
      if (this.curComp) {
        data = data[this.curComp];
      }
      const { dataSourceType } = data;

      if (['xMiner', 'xMinerPublicDatabase', 'fabric', 'Dac'].includes(dataSourceType)) {
        this.params.params = this.addAdvancedLinkageParamsBySourceType(dataSourceType, this.params.params || [], matchParams);
      } else if (dataSourceType === 'xTag') {
        this.addAdvancedLinkageParamsBySourceType(dataSourceType, this.params, matchParams);
      } else {}

      // 记录事件
      const fEvents = formatEvents(matchEvents);
      fEvents.forEach(n => {
        this.addReceivedEvents(n, 'advancedLinkage');
      });
    },

    // 获取默认值事件数组，暂时只用于类型筛选
    getAdvDfValEvents(matchEvents = null) {
      const { defaultValFrom, hasDefaultVal, defaultValEvent } = this.config.config.data || {};
      if (!hasDefaultVal || defaultValFrom !== 'event' || !defaultValEvent?.length) {
        return [];
      }
      let events = [];
      let _matchEvents = matchEvents;
      if (!_matchEvents) {
        _matchEvents = getMatchAdvEvents(this.config.events);
      }
      events = _matchEvents.filter(n => defaultValEvent.includes(n.evtKey));
      return events;
    },

    // 剔除默认值事件，这些事件不参与api查询
    clearAdvDfEvents(matchEvents) {
      const dfValEvents = this.getAdvDfValEvents(matchEvents);
      const evtKeys = dfValEvents.map(n => n.evtKey);
      const _matchEvents = matchEvents.filter(n => !evtKeys.includes(n.evtKey));
      return _matchEvents;
    },

    getMyEvents(linkageDatas, compEvtKeys) {
      const events = [];
      linkageDatas.forEach(n => {
        n.events.forEach(ev => {
          if (compEvtKeys.includes(ev.evtKey)) {
            const _ev = clone(ev);
            _ev.params.forEach(n1 => {
              delete n1.sendTime;
            });
            events.push(_ev);
          }
        });
      });
      return events;
    },

    loadAdvLinkageFromStorage() {
      if (window.visualComp.loadAdvLinkageDone) {
        return;
      }
      clearTimeout(window.visualComp.loadAdvLinkageTimer);
      window.visualComp.loadAdvLinkageTimer = setTimeout(() => {
        const storageKey = `visual_advancedLinkage_${getQueryValue('advLinkageId')}`;
        if (storageKey) {
          const linkageItem = storage.get(storageKey);
          if (linkageItem) {
            linkageItem.oldHasLink = linkageItem.hasLink; // 用于toolbar是否展示图标
            linkageItem.hasLink = false;
            store.commit('delAdvancedLinkageEvents', linkageItem.events); // 删除同名事件
            store.commit('setAdvancedLinkage', [linkageItem]);
          }
        }
        window.visualComp.loadAdvLinkageDone = true;
      }, 100);
    },

    sendAdvancedLinkagge(srcValues, advancedLinkage, extKey = '') {
      if (this.$refs && this.$refs.Tooltip) {
        this.$refs.Tooltip.hideTip(true);
      }

      let _advancedLinkage = advancedLinkage || {};
      if (isEmptyObject(_advancedLinkage)) {
        _advancedLinkage = this.config.advancedLinkage || {};
      }

      sendAdvancedLinkagge({
        srcValues: srcValues || {},
        wid: this.widgetInstanceId,
        widgetName: this.config.propertyPannelName,
        advancedLinkage: _advancedLinkage,
        extKey,
        vm: this,
      });
    },

    clearWidAdvLinkage() {
      this.delAdvancedLinkageByWid(this.widgetInstanceId);
    },

    // 获取发送者事件key数组
    getSentEvtKeys() {
      const evtKeys = [];
      const sentLinkageDatas = this.advancedLinkage.sentLinkageDatas || [];
      sentLinkageDatas.forEach(n => {
        n.events.forEach(ev => {
          evtKeys.push(ev.evtKey);
        });
      });
      return evtKeys;
    },

  },
};
